﻿package net.wangit.jdbc.transaction;

import java.sql.SQLException;

import net.wangit.jdbc.DB;
import net.wangit.jdbc.JDBCException;
import net.wangit.jdbc.Transaction;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * JDBC事务类
 * 
 * @author watson
 * Feb 12, 2010
 */
public class JDBCTransaction implements TransactionImplementor {

	private DB db;
	private boolean toggleAutoCommit;
	private boolean begun;
	private boolean commitFailed;
	private static final Log log = LogFactory
			.getLog(net.wangit.jdbc.transaction.JDBCTransaction.class);

	public JDBCTransaction() {
	}

	public Transaction begin(DB db) throws JDBCException {
		this.db = db;
		if (log.isDebugEnabled())
			log.debug("begin transaction");
		try {
			toggleAutoCommit = db.getConnection().getAutoCommit();
			if (log.isDebugEnabled())
				log.debug((new StringBuilder("current autocommit status:"))
						.append(toggleAutoCommit).toString());
			if (toggleAutoCommit) {
				db.getConnection().setAutoCommit(false);
				if (log.isDebugEnabled())
					log.debug("disabled autocommit");
			}
		} catch (SQLException e) {
			log.error("Begin failed", e);
			throw new TransactionException("Begin failed with SQL exception: ",
					e);
		}
		begun = true;
		return this;
	}

	public void commit() throws JDBCException {
		if (!begun)
			throw new TransactionException(
					"Transaction not successfully started");
		if (log.isDebugEnabled())
			log.debug("commit");
		try {
			db.getConnection().commit();
		} catch (SQLException e) {
			log.error("Commit failed", e);
			commitFailed = true;
			throw new TransactionException(
					"Commit failed with SQL exception: ", e);
		} finally {
			toggleAutoCommit();
		}
	}

	public void rollback() throws JDBCException {
		if (!begun)
			throw new TransactionException(
					"Transaction not successfully started");
		try {
			if (log.isDebugEnabled())
				log.debug("rollback");
			if (commitFailed)
				db.getConnection().rollback();
		} catch (SQLException e) {
			log.error("Rollback failed", e);
			throw new TransactionException(
					"Rollback failed with SQL exception: ", e);
		} finally {
			toggleAutoCommit();
		}
	}

	private void toggleAutoCommit() {
		try {
			if (toggleAutoCommit) {
				if (log.isDebugEnabled())
					log.debug("re-enabling autocommit");
				db.getConnection().setAutoCommit(true);
			}
		} catch (Exception sqle) {
			log.error("Could not toggle autocommit", sqle);
		}
	}

}
